home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / kernel / stfloppy.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  13KB  |  479 lines

  1. #if (CHIP == M68000)
  2. /*
  3.  * This file contains a driver for the Floppy Disk Controller (FDC)
  4.  * on the Atari ST. It uses the WD 1772 chip, modified for steprates.
  5.  * The driver supports two operations: read a block and write a block.
  6.  * It accepts two messages, one for reading and one for writing,
  7.  * both using message format m2 and with the same parameters:
  8.  *
  9.  *    m_type      DEVICE    PROC_NR     COUNT    POSITION  ADRRESS
  10.  * ----------------------------------------------------------------
  11.  * |  DISK_READ | device  | proc nr |  bytes  |  offset | buf ptr |
  12.  * |------------+---------+---------+---------+---------+---------|
  13.  * | DISK_WRITE | device  | proc nr |  bytes  |  offset | buf ptr |
  14.  * |--------------------------------------------------------------|
  15.  * |SCATTERED_IO| device  | proc nr | requests|         | iov ptr |
  16.  * ----------------------------------------------------------------
  17.  *
  18.  * The file contains two entry points:
  19.  *
  20.  *    floppy_task:    main entry when system is brought up
  21.  *    fd_timer:    used to deselect drives, called from clock.c
  22.  *
  23.  * The ST floppy disk controller shares the access to the DMA circuitry
  24.  * with other devices. For this reason the floppy disk controller makes
  25.  * use of some special DMA accessing code.
  26.  *
  27.  * Interrupts from the FDC are in fact DMA interrupts which get their
  28.  * first level handling in stdma.c . If the floppy driver is currently
  29.  * using DMA the interrupt is signalled to the floppy task.
  30.  */
  31.  
  32. #include "kernel.h"
  33. #include <minix/callnr.h>
  34. #include <minix/com.h>
  35. #include "proc.h"
  36.  
  37. #include "staddr.h"
  38. #include "stfdc.h"
  39. #include "stdma.h"
  40. #include "stsound.h"
  41.  
  42. #define    ASSERT(x)    if (!(x)) panic("fd: ASSERT(x) failed",NO_NUM);
  43. #define TRACE(x)    /* x */
  44. #define DEBUG(x)    x
  45.  
  46. #define    FDC_DELAY    32    /* for dma[rw]dat() */
  47.  
  48. /* Parameters for the disk drive. */
  49. #define TRACK_SIZE    7168    /* track size in bytes for formatting */
  50. #define SECTOR_SIZE    512    /* physical sector size in bytes */
  51. #define NR_SECTORS    9    /* number of sectors per track */
  52. #define NR_CYLINDERS    80    /* number of cylinders */
  53. #define NR_FLOPDRIVES    2    /* maximum number of drives */
  54. #define NR_TYPES    2    /* number of diskette/drive combinations */
  55. #define MAX_ERRORS    10    /* how often to try rd/wt before quitting */
  56.  
  57. /* return values of xfer_ok(): */
  58. #define X_OK        0
  59. #define X_AGAIN        1
  60. #define X_ERROR        2
  61. #define X_FAIL        3
  62.  
  63. PRIVATE int curcyl[NR_FLOPDRIVES];    /* current cylinder (-1 if not calibrated) */
  64.  
  65. PRIVATE message mess;        /* message buffer for in and out */
  66.  
  67. /*
  68.  * Two combinations of diskette/drive are supported:
  69.  *   # Drive  Diskette  Heads  Comment
  70.  *   0   Any      360K      1  Single Sided
  71.  *   1  720K      720K      2  Double Sided
  72.  */
  73. PRIVATE int nr_heads[NR_TYPES]    = {1,2};    /* tracks/cylinder */
  74.  
  75. PRIVATE struct xfer {
  76.     int    x_rw;        /* read or write */
  77.     int    x_drive;    /* drive number */
  78.     int    x_secnum;    /* current sector */
  79.     phys_bytes x_address;    /* current physical address */
  80.     int    x_count;    /* bytes still to transfer */
  81.     int    x_errors;    /* errors on current sector */
  82.     int    x_cmd;        /* controller command */
  83. } xfer;
  84.  
  85. #define    DRIVE(d)    ((d) & 0x07)
  86. #define    DTYPE(d)    (((d) >> 3) & 0x07)
  87. #define FORMAT(d)    ((d) & 0x40)
  88.  
  89. static int do_open();
  90. static int do_rdwt();
  91. static int do_xfer();
  92. static int select();
  93. static void deselect();
  94. static void fdcint();
  95. static int xfer_done();
  96. static int xfer_ok();
  97.   
  98. /*===========================================================================*
  99.  *                floppy_task                     *
  100.  *===========================================================================*/
  101. PUBLIC void floppy_task()
  102. {
  103.   register r, drive, caller, procno;
  104.  
  105.   /*
  106.    * The main loop of the disk task.
  107.    * It waits for a message, carries it out, and sends a reply.
  108.    */
  109.   TRACE(printf("fd: task started\n"));
  110.   dmagrab(FLOPPY, fdcint);
  111.   dmawdat(FDC_CS, IRUPT, FDC_DELAY);        /* reset controller */
  112.   dmafree(FLOPPY);
  113.   for (drive = 0; drive < NR_FLOPDRIVES; drive++)
  114.     curcyl[drive] = -1;    /* uncalibrated */
  115.   while (TRUE) {
  116.     receive(ANY, &mess);
  117.     ASSERT(mess.m_source >= 0);
  118.     TRACE(printf("fd: received %d from %d\n",mess.m_type,mess.m_source));
  119.     caller = mess.m_source;
  120.     procno = mess.PROC_NR;
  121.  
  122.     /* Now carry out the work. */
  123.     switch (mess.m_type) {
  124.         case DISK_READ:
  125.         case DISK_WRITE:    r = do_rdwt(&mess);    break;
  126.         case SCATTERED_IO:    r = do_vrdwt(&mess, do_rdwt); break;
  127.         default:        r = EINVAL;        break;
  128.     }
  129.  
  130.     /* Finally, prepare and send the reply message. */
  131.     mess.m_type = TASK_REPLY;    
  132.     mess.REP_PROC_NR = procno;
  133.     mess.REP_STATUS = r;    /* # of bytes transferred or error code */
  134.     send(caller, &mess);    /* send reply to caller */
  135.   }
  136. }
  137.  
  138.  
  139. /*===========================================================================*
  140.  *                do_rdwt                         *
  141.  *===========================================================================*/
  142. PRIVATE int do_rdwt(mp)
  143. register message *mp;
  144. {
  145.   register struct proc *rp;
  146.   register struct xfer *xp;
  147.   register nbytes;
  148.  
  149.   xp = &xfer;
  150.   xp->x_rw = mp->m_type;
  151.   xp->x_drive = mp->DEVICE;
  152.   if (DRIVE(xp->x_drive) >= NR_FLOPDRIVES)
  153.     return(EIO);
  154.   if (DTYPE(xp->x_drive) >= NR_TYPES)
  155.     return(EIO);
  156.   nbytes = mp->COUNT;
  157.   xp->x_count = nbytes;
  158.   if ((mp->POSITION % SECTOR_SIZE) != 0)
  159.     return(EINVAL);
  160.   if ((nbytes % SECTOR_SIZE) != 0)
  161.     return(EINVAL);
  162.   if (FORMAT(xp->x_drive)) {
  163.     if (nbytes != TRACK_SIZE || xp->x_rw != DISK_WRITE)
  164.         return(EINVAL);
  165.     xp->x_secnum = (int)(mp->POSITION/TRACK_SIZE);
  166.   }
  167.   else
  168.     xp->x_secnum = (int)(mp->POSITION/SECTOR_SIZE);
  169.   rp = proc_addr(mp->PROC_NR);
  170.   xp->x_address = umap(rp, D, (vir_bytes) mp->ADDRESS, (vir_bytes) nbytes);
  171.   if (xp->x_address == 0)
  172.     return(EINVAL);
  173.   if (nbytes == 0)
  174.     return(0);
  175.   rp->p_physio = 1;        /* disable (un)shadowing */
  176.   dmagrab(FLOPPY, fdcint);
  177.   xp->x_errors = 0;
  178.   if (do_xfer()) {
  179.     receive(HARDWARE, &mess);
  180.     deselect();
  181.   }
  182.   dmafree(FLOPPY);
  183.   rp->p_physio = 0;        /* enable (un)shadowing */
  184.   if (xp->x_count == nbytes)
  185.     return(0);        /* nothing transferred */
  186.   if (xp->x_count != 0)
  187.     return(EIO);        /* partial transfer */
  188.   return(nbytes);
  189. }
  190.  
  191. /*===========================================================================*
  192.  *                do_xfer                         *
  193.  *===========================================================================*/
  194. PRIVATE int do_xfer()
  195. {
  196.   register struct xfer *xp;
  197.   register d, head, cylinder, sector, hbit;
  198.  
  199.   xp = &xfer;
  200.  
  201.   d = DTYPE(xp->x_drive);
  202.   if (FORMAT(xp->x_drive))
  203.     cylinder = xp->x_secnum;
  204.   else
  205.     cylinder = xp->x_secnum / NR_SECTORS;
  206.   head = cylinder % nr_heads[d];
  207.   cylinder = cylinder / nr_heads[d];
  208.   if (cylinder >= NR_CYLINDERS)
  209.     return(0);
  210.  
  211.   d = DRIVE(xp->x_drive);
  212.  
  213.   hbit = 0;
  214.   if (select(d, head) != 0)
  215.     hbit = HBIT;    /* motor on, suppress spin up sequence */
  216.  
  217.   if (curcyl[d] == -1) {
  218.     /* 
  219.      * Recalibrate, since we lost track of head positioning.
  220.      * The floppy disk controller has no way of determining its
  221.      * absolute arm position (cylinder).  Instead, it steps the
  222.      * arm a cylinder at a time and keeps track of where it
  223.      * thinks it is (in software).  However, after a SEEK, the
  224.      * hardware reads information from the diskette telling
  225.      * where the arm actually is.  If the arm is in the wrong place,
  226.      * a recalibration is done, which forces the arm to cylinder 0.
  227.      * This way the controller can get back into sync with reality.
  228.      */
  229.     TRACE(printf("fd%d: recalibrate\n", xp->x_drive));
  230.     if (FORMAT(xp->x_drive))
  231.         dmawdat(FDC_CS, RESTORE|hbit, FDC_DELAY);
  232.     else
  233.         dmawdat(FDC_CS, RESTORE|VBIT|hbit, FDC_DELAY);
  234.     xp->x_cmd = RESTORE;
  235.     return(1);
  236.   }
  237.  
  238.   dmawdat(FDC_TR, curcyl[d], FDC_DELAY);
  239.  
  240.   /*
  241.    * Issue a SEEK command on the indicated drive unless the arm is
  242.    * already positioned on the correct cylinder.
  243.    */
  244.   if (cylinder != curcyl[d]) {
  245.     curcyl[d] = cylinder;    /* be optimistic */
  246.     dmawdat(FDC_DR, cylinder, FDC_DELAY);
  247.     if (FORMAT(xp->x_drive)) {
  248.         if (cylinder == 0)
  249.             dmawdat(FDC_CS, RESTORE|hbit, FDC_DELAY);
  250.         else
  251.             dmawdat(FDC_CS, SEEK|RATE3|hbit, FDC_DELAY);
  252.     }
  253.     else
  254.         dmawdat(FDC_CS, SEEK|RATE3|VBIT|hbit, FDC_DELAY);
  255.     xp->x_cmd = SEEK;
  256.     return(1);
  257.   }
  258.  
  259.   TRACE(printf("fd%d: %s: secnum=%d,cylinder=%d,sector=%d,head=%d\n",
  260.     xp->x_drive, xp->x_rw == DISK_READ ? "read" : "write",
  261.     xp->x_secnum, cylinder, sector, head));
  262.  
  263.   /* The drive is now on the proper cylinder.  Read